///@file Node.cpp
///@brief Implementation of the class representing a mesh Node
///@author Arnaud Duval
///@version 0.0
///@date 2009/10/29

#include "Node.h"

#include <cmath>


///@brief Default constructor
Node::Node()
{
	dim = 0;
	reference = "0";
}

///@brief Constructor with a predefined dimension
///@param d Dimension
Node::Node(int d)
{
	dim = d;
	reference = "0";
	coords = new double[dim];
}

///@brief Copy constructor
///@param n Node object to copy
Node::Node(const Node& n)
{
	assert(n.dim != 0);
	dim = n.dim;
	reference = n.reference;
	coords = new double[dim];
	for(unsigned int i = 0 ; i < dim ; i++)
	{
		coords[i] = n.coords[i];
	}
}

///@brief Copy constructor for temporary objects
///@param n Temporary Node object to copy
Node::Node(Node* n)
{
	assert((*n).dim != 0);
	dim = (*n).dim;
	reference = (*n).reference;
	coords = new double[dim];
	for(unsigned int i = 0 ; i < dim ; i++)
	{
		coords[i] = (*n).coords[i];
	}
}

///@brief Destructor
Node::~Node()
{
	if(dim != 0)
		delete[] coords;
}

///@brief Direct access to reference
std::string& Node::Reference()
{
	return reference;
}

///@brief Return dimension of node coordinates
int Node::Dim()
{
	return dim;
}

///@brief Set dimension of coordinates array
///@param givenDimension New dimension of coordinates array
void Node::SetDimension(unsigned int givenDimension)
{
	if(dim != 0)
		delete[] coords;
	dim = givenDimension;
	coords = new double[dim];
}

///@brief Set a given coordinates
///@param idx Index of cordinate to set
///@param val New value of coordinate
void Node::SetCoordinate(unsigned int idx, double val)
{
	assert((idx > 0)&&(idx <= dim));
	coords[idx-1] = val;
}

///@brief Return a given coordinate
///@param idx Index of coordinate to return
double Node::GetCoordinate(unsigned int idx)
{
    assert((idx > 0)&&(idx <= dim));
    return coords[idx-1];
}

///@brief Overload of [] operator : direct access to a coordinate
///@param idx index of required coordinate
double& Node::operator[] (unsigned int idx)
{
	assert((idx > 0)&&(idx <= dim));
	return coords[idx-1];
}

///@brief Overload of = operator
///@param n Right hand operand
Node& Node::operator= (const Node n)
{
	assert (n.dim != 0);
	dim = n.dim;
	reference = n.reference;
	coords = new double[dim];
	for(unsigned int i = 0 ; i < dim ; i++)
		coords[i] = n.coords[i];
	return (*this);
}

///@brief Overload of = operator for temporary objects
///@param n Right hand operand
Node& Node::operator= (Node* n)
{
	assert ((*n).dim != 0);
	dim = (*n).dim;
	reference = (*n).reference;
	coords = new double[dim];
	for(unsigned int i = 0 ; i < dim ; i++)
		coords[i] = (*n).coords[i];
	return (*this);
}

///@brief Return number of DOF of the node
///@warning For the moment, this function always return 2 for tests
unsigned int Node::GetNumberOfDOF()
{
    return 2u;
}

///@brief Compute distance between 2 nodes
///@param n1 First node
///@param n2 Second node
double Distance(const Node& n1, const Node& n2)
{
	assert(n1.dim == n2.dim);
	double dist = 0.;
	for(unsigned int i = 0 ; i < n1.dim ; i++)
	{
		dist += pow(n1.coords[i] - n2.coords[i],2.);
	}
	dist = sqrt(dist);

	return dist;
}


///@brief Overload of << operator
///@param s out stream
///@param n Node object to put in the out stream
std::ostream& operator<<(std::ostream& s, Node& n)
{
	s << n.reference.c_str() << " : \t" ;
	for(unsigned int i = 0 ; i < n.dim ; i++)
		s << n.coords[i] << "\t";
	return s;
}

